(function() {
	
    var 

        K = function() {
            if (!arguments.length) {
                return this;
            }
            
            switch (typeof arguments[0]) {
                case "function" :
                    asap(arguments[0]);
                    return this;
            }
        },
        
        /**
         * A simple configuration map
         * @param {string#}
         */
        config = {
        	path : "./"
        },
        
        reservedIdentifiers = {},
    
        /**
         * A reference to the global object
         * @type {object} 
         */
         global = (function() { return this; }()),
    
        /**
         * A reference to the Object's prototype
         * @type {object}
         */
        objectProto = Object.prototype,
        
        /**
         * An undefined reference
         * @type {undefined}
         */
        undefined,
    
        /**
         * Creates a descendant relationship between the constructors
         * 
         * @param {function} descendant
         * @param {function} kin
         */
        descend = function(descendant, kin) {
            var f = function() {};
            f.prototype = kin.prototype;
            descendant.prototype = new f();
            descendant.prototype.constructor = descendant;
            descendant.ancestor = kin.prototype;
        },
        
        /**
         * Creates a new instance using the kin's constructor and the list of arguments used to it
         * 
         * @param {function} kin
         * @param {mixed[]} args
         * @return {mixed}
         */
        create = function(kin, args) {
        	var f = function() {
        		kin.apply(this, args);
        	};
        	
        	descend(f, kin);
        	f.prototype.constructor = kin;
        	
        	return new f();
        },
        
        /**
         * Returns the logger instance for a given name
         * 
         * @param {string} name
         * @return {K.logging.Logger}
         */
        logger = function(name) {
        	return K.logging.Logger.getLogger(name);
        },
        
        /**
         * Returns a function that logs a message with fatal level and throws an error with the same message
         * 
         * @param {string} loggerName
         * @return {function}
         */
        killer = function(loggerName) {
            return function(method, message) {
                var msg = "[" + method + "] " + message;
                logger(loggerName).fatal(msg);
                throw loggerName + " | " + message;
            };        	
        },
        
        /**
         * Iterates over a string, object or an array calling the f function on each pass
         * 
         * @param {string|array|object} o
         * @param {function} f
         */
        forEach = function(o, f) {
        	var i, l, msg;
        	if (objectProto.toString.call(o) === "[object Array]" ) {
        		for (i = 0, l = o.length; i < l; i += 1) {
        			f(o[i], i);
        		}
        	} else if ((typeof o === "string") || (o instanceof String)) {
        		o = new String(o);
        		for (i = 0, l = o.length; i < l; i += 1) {
        			f(o.charAt(i), i);
        		}
        	} else if ((typeof o === "object") || (typeof o === "function")) {
        		for (var a in o) {
        			if (o.hasOwnProperty(a)) {
        				f(o[a], a);
        			}
        		}
        	} else {
            	msg = "[#forEach] Unknown o:" + o;
            	logger("K").error(msg);
            	throw "K | " + msg;
        	}
        },
        
        /**
         * Merges the properties from o2 into o1
         * 
         * @param {object} o1
         * @param {object} o2
         */
        merge = function(o1, o2) {
        	for (var a in o2) {
        	    if (o2.hasOwnProperty(a)) {
        	        o1[a] = o2[a];
        	    }
        	}
        },
        
        configMeta = function() {
        	forEach(array(document.getElementsByTagName("meta")), function(meta) {
                var name = meta.getAttribute("name");
                
                if (name) {
                    name = meta.getAttribute("name").match(/^K:(.*)/)[1];
                    if (name) {
                    	config[name] = meta.getAttribute("content");
                    }
                }
        	});
        },
        
        /**
         * Creates new classes of things
         * 
         * @param {function}
         *            creator The creator function that will receive the new
         *            blank object as first parameter and the subsequent
         *            arguments from the caller
         * 
         * @return {function} A new kin, or class if you may
         */
        kin = function(creator, name) {
            var kin = function() {
                var args = array(arguments);
                if (!(this instanceof kin)) {
                    return create(kin, args);
                }
                
                args.unshift(this);
                creator.apply(null, args);
            };
            
            kin.prototype.constructor = kin;
            
            kin.descend = function(creator) {
                var descendant = K.kin(creator);
                descend(descendant, kin);
                return descendant;
            };
            
            return kin;
        },
        
        /**
         * Fires the function as soon as the document is ready to be manipulated (DOMContentLoaded is fired)
         * 
         * @param {function} f The callback function to be run when possible
         */
        asap = (function() {
            var callbacks = [], 
                loaded = false;
            
            if (/interactive|loaded/.exec(document.readyState)) {
                return function(f) {
                    f();
                };
            }
            
            document.addEventListener("DOMContentLoaded", function() {
                loaded = true;
                forEach(callbacks, function(f) {
                    f();
                });
                callbacks = null;
            }, false);
            
            return function(f) {
                if (loaded) {
                    f();
                } else {
                    callbacks.push(f);
                }
            };
        }()),
        
        /**
         * Returns the safe node for insertion point. Either it returns the
         * first ocurrence with the tagName or the document's body element
         * 
         * @param {HTMLDocument}
         *            doc the parent document
         * @param {string}
         *            tagName the chosen tagName
         * @return {HTMLElement}
         */
        getInsertionPoint = function(doc, tagName) {
            return doc.getElementsByTagName(tagName)[0] || doc.documentElement;
        },
        
        /**
         * Includes a script into the DOM
         * 
         * @param {HTMLDocument}
         *            doc The parent document
         * @param {string}
         *            script Script url
         * @param {function}
         *            success Callback function executed after the script is
         *            included and loaded
         * 
         */
        includeScript = function(doc, script, success) {
            var insertionPoint = getInsertionPoint(doc, "head"),
                node = doc.createElement("script");
                
            track(node, success);
            node.src = script;
            insertionPoint.insertBefore(node, insertionPoint.firstChild);
            return node;
        },
        
        /**
         * Tracks the loading of a script element. When the script is loaded and
         * run, first the "success" callback
         * 
         * @param {HTMLScriptElement}
         *            node the "script" node
         * @param {function}
         *            success the success callback function
         */
        track = (function() {
            if ((function(m) { return m && m[1]; })(navigator.userAgent.match(/MSIE\s([^;]*)/)))
                return function(node, success) {
                    var check = function(rs) {
                        if ("loaded" == rs || "complete" == rs) {
                            success();
                        }
                    };
        
                    check(node.readyState);
                    node.onreadystatechange = function() { check(this.readyState); };
                };
                
            if (/KHTML/.test(navigator.userAgent)) { 
                return function(node, success) {
                    node.addEventListener("load", success, false);          
                };
            }
                
            return function(node, success) {
                node.onload = success;
            };
        }()),
        
        /**
         * A simple id provider constructor
         */
        IdProvider = kin(function(obj) {
            var chars = "abcdefghijklmnopqrstwxyzABCDEFGHIJKLMNOPQRSTWXYZ",
                length = chars.length,
                lastChar = chars.charAt(chars.length - 1),
                firstChar = chars.charAt(0),
                id = [];
            
            obj.next = function() {
                var i, c;
                for (i = id.length - 1; i > -1; i -= 1) {
                    c = id[i];
                    if (c !== lastChar) {
                        id[i] = chars.charAt(chars.indexOf(c) + 1);  
                        break;
                    }
                    
                    id[i] = firstChar;
                }
                
                if (i === -1) {
                    id.unshift(firstChar);
                }
                
                return id.join("");
            };
        }),
        
        /**
         * Main class responsible for loading subsequent scripts. When it's done loading
         * all it's stuff, it executes the scheduled callbacks.
         */
        Loader = kin(function(obj) {
            var 
                scripts = [],
                successCallbacks = [],
                
                loaded = false,
            
                includeScripts = function(success) {
                    var l = scripts.length,
                        i = 0,
                        call = function() {
                            includeScript(document, scripts[i], function() {
                                i += 1;
                                if (i < l) {
                                    call(); 
                                } else {
                                    success();
                                }
                            });
                        };
                    
                    call();
                };
                
            merge(obj, {
                /**
                 * Adds a script to be loaded
                 * 
                 * @param {string}
                 *            script
                 * @return {K.util.Loader}
                 */
                load : function(script) {
                    scripts.push(script);
                    return obj;
                },
                
                /**
                 * Wait until we have all scripts loaded to run this payload
                 * 
                 * @param {function}
                 *            f Payload to run
                 * @return {K.util.Loader}
                 */
                run : function(f) {
                    if (loaded) {
                        runCallback(f);
                    } else {
                        successCallbacks.push(f);
                    }
                    
                    return obj;
                },
        
                /**
                 * Load it's scripts and run it's payload.
                 */
                go : function() {
                    var func = function() {
                        var i = 0,
                            l = successCallbacks.length;
                        
                        
                        while (i < l) {
                            successCallbacks[i]();
                            i += 1;
                        }
                            
                        loaded = true;
                    };
                    
                    if (loaded) {
                        return;
                    }
                    
                    includeScripts(func);
                }
            });
        }),
        
        array = function(arr) {
        	return Array.prototype.slice.call(arr);
        },
        
        kinExists = function(name) {
            var parts = name.split("."),
                o = global,
                i, 
                l, 
                part;
                
            for (i = 0, l = parts.length; i < l; i += 1) {
                part = parts[i];
                if (!objectProto.hasOwnProperty.call(o, part)) {
                    return false;
                }
                o = o[part];
            }
            
            return true;
        },
        
        /**
         * Map containing all preloaded kins
         * @type {undefined#}
         */
        preloaded = {},
        
        /**
         * Adds all kins to the preloaded map
         * 
         * @param {string...} kin
         */
        preload = function() {
        	forEach(array(arguments), function(kin) {
        		preloaded[kin] = true;
        	});
        },
        
        /**
         * Retrieves and provides resources across the framework
         * 
         *  @param {string} resource
         *  @return {string}
         */
        resource = (function() {
            var resources = {};
            
            return function(resource) {
                if (!(resource in resources)) {
                    var xhr = new XMLHttpRequest();
                    xhr.open("GET", config.path + resource, false);
                    xhr.send();
                    resources[resource] = xhr.responseText; 
                }
                
                return resources[resource];
            };
        }()),
        
        /* Kin declaring and loading facilities */
        
        DependencyResolver = (function() {
            var 

                /**
                 * Id that gives ids to the resolver intances
                 * @type {K.util.IdProvider}
                 */
                idProvider = IdProvider(),
            
                /**
                 * Map contanining all resolvers
                 * @type {DependencyResolver#}
                 */
                resolvers = {},
                
                /**
                 * Map containing resolvers that provides a kin
                 * @type {DependencyResolver#}
                 */
                kinResolvers = {},
            
                /**
                 * Map containing all declared kin
                 * @type {object}
                 */
                kinMap = { "K" : K },
                
                /**
                 * Fires all resolvers related with a given kin
                 * 
                 * @param {string} kin
                 */
                triggerResolvers = function(kin) {
                	forEach(resolvers, function(resolver) {
                		if (resolver.needsKin(kin)) {
                			resolver.triggerExecution();
                		}
                	});
                },
                
                hasDependenciesLeft = function(resolver, includeMap) {
                    var provides = resolver.getProvides(),
                        remainingIncludes = resolver.getRemainingIncludes(includes);
                        
                    if (!includeMap) {
                        includeMap = {};
                    }
                        
                    if (!resolver.hasRun()) {
                        return true;
                    }

                    if (resolver.getRemainingRequires().length) {
                    	return true;
                    }
                    
                    if (provides) {
                        includeMap[provides] = resolver;
                    }
                    
                    return remainingIncludes.some(function(kin) {
                        var resolver = kinResolvers[kin];
                        
                        if (!resolver) {
                            return true;
                        }
                        
                        if (includeMap[kin]) {
                            return false;
                        }
                        
                        if (hasDependenciesLeft(resolver, includeMap)) {
                            return true;
                        }
                        
                        return false;
                    });
                },
                
                /**
                 * Gives the kin name out of its box
                 * 
                 * @param {string} kin
                 * @return {string}
                 */
                simplifiedKinName = function(kin) {
                	return kin.split(".").pop();
                },
                
                /**
                 * Logs a message with fatal level and throws an error
                 * 
                 * @param {string} method
                 * @param {string} message
                 */
                die = killer("DependencyResolver"),
                
                /**
                 * Returns the reference for a given kin name
                 * 
                 * @param {string} name
                 * @return {function}
                 */
                getKin = function(name) {
                	var o = global;
                	forEach(name.split("."), function(part) {
                		if (!objectProto.hasOwnProperty.call(o, part)) {
                			die("getKin", "Kin not found: " + name);
                		}
                		
                		o = o[part];
                	});
                	
                    return o;
                },
                
                /**
                 * Checks if a given identifier clashes with a reserved identifier
                 * 
                 * @param {string} kin
                 */
                checkIdentifier = function(kin) {
                	forEach(reservedIdentifiers, function(o, identifier) {
                		if (kin.indexOf("K." + identifier) === 0) {
                			die("checkIdentifier", "Unable declare the kin starting with a reserved identifer within K: " + kin);
                		}
                	});
                },
                
                /**
                 * Ensures that a given kin will be loaded eventually
                 * 
                 * @param {string} kin
                 */
                ensureKinLoading = function(kin) {
                	if (preloaded[kin]) {
                		return;
                	}
                	
                	loadExternalKin(kin);
                },
                
                loadExternalKin = function(kin) {
                	preloaded[kin] = true;
                	Loader().
                    	load(config.path + kin.replace(/\./g, "/") + ".js").
                    	go();
                },
                
                /**
                 * Creates the box tree for a give path
                 * 
                 * @param {string} box
                 * @return {object}
                 */
                box = function(box) {
                    var o = global;
                    forEach(box.split("."), function(part) {
                        o = o[part] = o[part] || {};
                    });
                    return o;
                },
                
                /**
                 * Returns the box tree for a given kin name
                 * 
                 * @param {string} name
                 * @return {string}
                 */
                kinBox = function(name) {
                	return name.replace(/^(([^\.]+\.)*[^\.]+)\.[^\.]+$/, "$1");
                };
                
            return kin(function(o, includes, requires, provides, payload) {
                var 
                
                    /**
                     * Id associated with this resolver
                     * @type {number}
                     */
                    id = idProvider.next(),
                    
                    /**
                     * Timeout Id associated with the current resolver
                     * @type {number}
                     */
                    timeoutId = setTimeout(function() { timeout(); }, 5000),
                       
                    /**
                     * Indicates whether this resolver has already run
                     * @type {boolean} 
                     */
                    hasRun = false,
                    
                    /**
                     * Indicates wheter this resolver is trying to execute
                     * @type {boolean}
                     */
                    executing = false,
        	       
                    /**
                     * Map that handles all required references
                     * @type {function#}
                     */
                    required = {},
                    
                    /**
                     * Map that handles all included references
                     * @type {function#}
                     */
                    included = {},
                    
                    /**
                     * Map that handles all imported references 
                     * @type {function#}
                     */
                    imports = {},
                    
                    /**
                     * Fires the whole process
                     */
                    run = function() {
                    	if (provides) {
                    		try {
                        		checkIdentifier(provides);
                    		} catch(e) {
                    			clearTimeout(timeoutId);
                    			throw e;
                    		}
                    	}
                        populateAliases();
                        scheduleExecution();
                    },

                    /**
                     * Creates the imports map with the includes and requires map 
                     */
                    populateAliases = function() {
                        populateAliasMap(includes);
                        populateAliasMap(requires);
                    },
                    
                    /**
                     * Populates the imports map with a given dependency map
                     * 
                     * @param {string#} map
                     */
                    populateAliasMap = function(map) {
                        forEach(map, function(alias, kin) {
                        	var msg;
                        	
                            if (!alias) {
                                alias = simplifiedKinName(kin);
                            }
                            
                            if (imports.hasOwnProperty(alias)) {
                            	die("populateAliasMap", "Alias-clash: " + alias);
                            }
                            
                            map[kin] = alias;
                            imports[alias] = undefined;
                        });
                    },
                    
                    /**
					 * Registers this resolver within the registry and triggers
					 * it's execution whenever possible
					 */
                    scheduleExecution = function() {
                        resolvers[id] = o;
                        if (provides) {
                        	mapKin();
                        	kinResolvers[provides] = o; 
                        }
                        o.triggerExecution();
                    },
                    
                    /**
                     * Register the resolver within the kinMap
                     */
                    mapKin = function() {
                    	var msg;
                        if (kinMap.hasOwnProperty(provides)) {
                        	die("mapKin", "Kin-clash: " + provides);
                        }
                        kinMap[provides] = undefined;
                    },
                    
                    /**
                     * Tries to resolve all dependencies
                     * 
                     * @param {string#} dependencies
                     * @param {string#} resolvedDependencies
                     * @param {function} checkReady
                     */
                    resolveDependencies = function(dependencies, resolvedDependencies, checkReady) {
                    	forEach(dependencies, function(alias, kin) {
                            if (resolvedDependencies.hasOwnProperty(kin)) {
                                return;
                            }
                            
                            if (!checkReady(kin)) {
                            	ensureKinLoading(kin);
                                return;
                            }
                            
                            imports[alias] = getKin(kin);
                            resolvedDependencies[kin] = undefined;
                    	});
                    },
                    
                    /**
                     * Returns the list of dependencies not yet loaded
                     * 
                     * @param {string#} dependencies
                     * @return {string[]}
                     */
                    getRemainingDependencies = function(dependencies) {
                    	var remainingDependencies = [];
                    	forEach(dependencies, function(alias, kin) {
                            if (!kinMap[kin]) {
                                remainingDependencies.push(kin);
                            }
                    	});

                        return remainingDependencies;
                    },
                    
                    checkDependencyCycle = function() {
                        var visitedResolvers, visit;
                        
                    	if (!provides) {
                    		return;
                    	}
                        
                        visitedResolvers = {};
                        
                        visit = function(alias, kin) {
                            var resolver, requires, includes;
                            
                            if (!kin in kinResolvers) {
                                return;
                            }
                            
                            resolver = kinResolvers[kin];
                            if (!resolver) {
                                return;
                            }
                            
                            if (kin in visitedResolvers) {
                                return;
                            }
                            visitedResolvers[kin] = resolver;
                            
                            requires = resolver.getRequires();
                            includes = resolver.getIncludes();
                            if (requires.hasOwnProperty(provides) || includes.hasOwnProperty(provides)) {
                                die("checkDependencies", 'Cycle detected within kin "' + kin + '" while loading kin "' + provides + '"');
                            }
                            
                            forEach(requires, visit);
                            forEach(includes, visit);
                        };
                    	
                    	forEach(requires, visit);
                    },
                    
                    timeout = function() {
                        var dependencies = getRemainingDependencies(requires).concat(getRemainingDependencies(includes)),
                            msg = 
                                (provides ? "Kin " + provides : "Payload") + 
                                " timeouted" + (dependencies.length ? " waiting on the following dependencies: " + dependencies.join(", ") : "...");
                                
                        die("timeout", msg);
                    };                    
                        
                merge(o, {
                	
                	/**
                	 * Tries to execute the resolver's payload if possible
                	 */
                    triggerExecution : function() {
                        var b,
                            r;
                            
                        if (executing) {
                            return;
                        }
                        
                        running = true;
                        try {
                            try {
                                checkDependencyCycle();
                            } catch (e) {
                                clearTimeout(timeoutId);
                            	throw e;
                            }
                            
                            resolveDependencies(includes, included, function(kin) { return kinExists(kin); });
                            
                            if (!hasRun) {
                                resolveDependencies(requires, required, function(kin) { return Boolean(kinMap[kin]); });
                                
                                if (!(o.getRemainingRequires().length)) {
                                    if (provides) {
                                        b = box(kinBox(provides));
                                        imports.provides = provides;
                                    }
                                    
                                    try {
                                        r = payload(imports);
                                    } catch(e) { 
                                        clearTimeout(timeoutId);
                                        throw e;
                                    }
                                    
                                    if (provides && !kinExists(provides)) {
                                        if (r) {
                                            b[simplifiedKinName(provides)] = r;
                                        } else {
                                        	die("triggerExecution", "No kin created: " + provides);
                                        }
                                    }
                                    hasRun = true;
                                }
                            }
                            
                            if (hasRun && !hasDependenciesLeft(o)) {
                            	if (provides) {
                            		kinMap[provides] = getKin(provides);
                            		delete kinResolvers[provides];
                            	}
                            	delete resolvers[id]
                                clearTimeout(timeoutId);
                            }
                            
                            if (provides) {
                                triggerResolvers(provides);
                            }
                        } finally {
                        	executing = false;
                        }
                    },
                    
                    /**
                     * Indicates whether this resolver needs a given kin
                     * 
                     *  @param {string} kin
                     *  @return {boolean}
                     */
                    needsKin : function(kin) {
                        return requires.hasOwnProperty(kin) || includes.hasOwnProperty(kin);
                    },
                    
                    /**
                     * Returns the includes map
                     * 
                     * @return {string#}
                     */
                    getIncludes : function() {
                    	return includes;
                    },
                    
                    /**
                     * Returns the requires map
                     * 
                     * @return {string#}
                     */
                    getRequires : function() {
                    	return requires;
                    },
                    
                    /**
                     * Returns the provides, if any
                     * 
                     * @return {string}
                     */
                    getProvides : function() {
                    	return provides;
                    },
                    
                    /**
                     * Returns a list of remaining includes to fulfill the resolver
                     * 
                     * @return {string[]}
                     */
                    getRemainingIncludes : function() {
                        return getRemainingDependencies(includes);
                    },
                    
                    /**
                     * Returns a list of remaining requires to fulfill the resolver
                     * 
                     * @return {string[]}
                     */
                    getRemainingRequires : function() {
                        return getRemainingDependencies(requires);
                    },
                    
                    /**
                     * Indicates whether this resolver has already run its payload
                     * 
                     * @return {boolean}
                     */
                    hasRun : function() {
                        return hasRun;
                    }
                    
                });
                    
                    
                run();
            });
            
            return DependencyResolver;
        }()),
        
        DependencyMapper = kin(function(o) {
            var includes = {},
                requires = {},
                provides;
                
            merge(o, {
                includes : function(kin, alias) {
                    includes[kin] = alias;
                    return o;
                },
                
                requires : function(kin, alias) {
                    requires[kin] = alias;
                    return o;
                },
                
                provides : function(kin) {
                    provides = kin;
                    return o;
                },
                
                run : function(payload) {
                    DependencyResolver(includes, requires, provides, payload);
                },
                
                asap : function(payload) {
                    o.run(function(I) {
                        asap(function() {
                            payload(I);
                        });
                    });
                }
            });
        }),
        
        includes = function(kin, alias) {
            return DependencyMapper().includes(kin, alias);
        },
        
        provides = function(kin) {
            return DependencyMapper().provides(kin);
        },
        
        requires = function(kin, alias) {
            return DependencyMapper().requires(kin, alias);
        },
        
        run = function(load) {
            DependencyMapper().run(load);
        };
        
    /* public API */
    merge(K, {
        global : global,
        asap : asap,
        kin : kin,
        resource : resource,
        
        logger : logger,
        killer : killer,
        
        array : array,
        merge : merge,
        forEach : forEach,
        
        includes : includes,
        provides : provides,
        run : run,
        requires : requires
    });
    
    /* declares reserved identifiers */
    merge(reservedIdentifiers, K);
    
    /* publishes crap */
    global.K = K;
    
    /* Publishes the IdProvider */
    K.provides("K.util.IdProvider").run(function() {
        return IdProvider;
    });
    
    /* Publishes the Loader */
    K.provides("K.util.Loader").run(function() {
        return Loader;
    });
    
    /* load meta configuration */
    configMeta();
    
    /* Ensures that we have logging facilities */
    K.
    requires("K.logging.Logger").
    requires("K.logging.Appender").
    run(function() {});
    
}());